﻿using System;
using System.Linq;
using fastCSharp;
using System.Collections.Generic;

namespace diantou.dataModel
{
    /// <summary>
    /// OJ提交
    /// </summary>
    [fastCSharp.emit.jsonSerialize(IsAllMember = true)]
    [fastCSharp.emit.jsonParse(IsAllMember = true)]
    [fastCSharp.code.cSharp.webView.clientType(Name = "diantou.judgeState")]
    [fastCSharp.emit.dataSerialize(IsReferenceMember = false, IsMemberMap = false)]
    [fastCSharp.code.cSharp.sqlModel]
    public partial class judgeState : judgeBase
    {
        /// <summary>
        /// 提交标识
        /// </summary>
        [fastCSharp.code.cSharp.webView.outputAjax]
        public int Id;
        /// <summary>
        /// 问题标识
        /// </summary>
        public int ProblemId;
        /// <summary>
        /// 用户标识
        /// </summary>
        public int UserId;
        /// <summary>
        /// 比赛/考试标识
        /// </summary>
        public int ContestId;
        /// <summary>
        /// 提交时间
        /// </summary>
        public DateTime SubmitTime;
        /// <summary>
        /// 程序语言
        /// </summary>
        public sealed class language : Attribute
        {
            /// <summary>
            /// 时间限制倍数
            /// </summary>
            public int Time;
            /// <summary>
            /// 内存限制倍数
            /// </summary>
            public int Memory;
            /// <summary>
            /// 程序扩展名
            /// </summary>
            public string ExtensionName;
        }
        /// <summary>
        /// 程序语言
        /// </summary>
        public enum languageType : byte
        {
            All = 0,
            [language(Time = 2, Memory = 2, ExtensionName = "c")]
            C = 1,
            [language(Time = 2, Memory = 2, ExtensionName = "c")]
            C11 = 2,
            [language(Time = 2, Memory = 2, ExtensionName = "cpp")]
            CPlus = 11,
            [language(Time = 2, Memory = 2, ExtensionName = "cpp")]
            CPlus11 = 12,
            [language(Time = 3, Memory = 3, ExtensionName = "cs")]
            CSharp = 21,
            [language(Time = 6, Memory = 4, ExtensionName = "java")]
            Java = 31,
            [language(Time = 10, Memory = 4, ExtensionName = "py")]
            Python2 = 41,
            [language(Time = 10, Memory = 4, ExtensionName = "py")]
            Python3 = 42,
            [language(Time = 6, Memory = 4, ExtensionName = "py")]
            PyPy2 = 45,
            [language(Time = 6, Memory = 4, ExtensionName = "py")]
            PyPy3 = 46,
            [language(Time = 10, Memory = 4, ExtensionName = "rb")]
            Ruby = 51,
            [language(Time = 9, Memory = 4, ExtensionName = "php")]
            Php = 61,
            [language(Time = 5, Memory = 4, ExtensionName = "hs")]
            Haskell = 71,
            [language(Time = 7, Memory = 4, ExtensionName = "scala")]
            Scala = 81,
            [language(Time = 10, Memory = 4, ExtensionName = "js")]
            Javascript = 91,
            [language(Time = 4, Memory = 4, ExtensionName = "go")]
            Go = 101,
            [language(Time = 2, Memory = 2, ExtensionName = "cpp")]
            VCPlus = 111,
            [language(Time = 2, Memory = 2, ExtensionName = "m")]
            OC = 121,
            [language(Time = 2, Memory = 2, ExtensionName = "pas")]
            Pascal = 131
        }
        /// <summary>
        /// 程序语言
        /// </summary>
        public languageType Language;
        /// <summary>
        /// 最大程序内容长度
        /// </summary>
        public const int MaxProgramContentLength = 64 * 1024;
        /// <summary>
        /// 测试状态
        /// </summary>
        public enum state : byte
        {
            WaitForCompile = 0,
            Compiling = 1,
            Compiled = 2,
            CompileError = 3,
            WaitForRun = 4,

            Complete = 16,
            SpecialJudgeProgramLost = 17,
            ZeroTest = 18,
            Crash = 19
        }
        /// <summary>
        /// 测试状态
        /// </summary>
        public state State;
        /// <summary>
        /// 允许其他人查看提交的代码
        /// </summary>
        public bool IsPublic;
        /// <summary>
        /// 是否测试结束
        /// </summary>
        public bool IsFinished;
        ///// <summary>
        ///// AC问题后发布到微博
        ///// </summary>
        //public bool IsMicroblog;
        /// <summary>
        /// 评论数
        /// </summary>
        public int CommentCount;
        /// <summary>
        /// ReTry次数
        /// </summary>
        [fastCSharp.emit.dataSerialize.member(IsIgnoreCurrent = true)]
        public byte RetryCount;
        /// <summary>
        /// 测试错误数量
        /// </summary>
        public byte ErrorCount;
        /// <summary>
        /// 测试数据数量
        /// </summary>
        public byte TestCount;

        /// <summary>
        /// 编译信息
        /// </summary>
        [fastCSharp.emit.dataSerialize.member(IsIgnoreCurrent = true)]
        [fastCSharp.emit.dataMember(Group = 1, IsIgnoreMaxStringLength = true)]
        public string Message = string.Empty;
        /// <summary>
        /// 程序内容
        /// </summary>
        [fastCSharp.emit.dataMember(Group = 1, MaxStringLength = MaxProgramContentLength)]
        public string ProgramContent;

        /// <summary>
        /// 提交前的排名
        /// </summary>
        [fastCSharp.emit.dataMember(IsIgnoreCurrent = true)]
        public int BeforeRank;
        /// <summary>
        /// 提交后的排名
        /// </summary>
        [fastCSharp.emit.dataMember(IsIgnoreCurrent = true)]
        public int AfterRank;
        /// <summary>
        /// 测试完成时间
        /// </summary>
        [fastCSharp.emit.dataMember(IsIgnoreCurrent = true)]
        public DateTime FinishedTime;
        /// <summary>
        /// 赞成数
        /// </summary>
        [fastCSharp.emit.dataMember(IsIgnoreCurrent = true)]
        public int AgreeCount;


        /// <summary>
        /// 
        /// </summary>
        public void SetJudgeValue()
        {
            OnlineJudge.JudgeState state;
            switch (State)
            {
                case dataModel.judgeState.state.Compiled:
                    state = OnlineJudge.JudgeState.Compiled;
                    break;
                case dataModel.judgeState.state.CompileError:
                    state = OnlineJudge.JudgeState.CompileError;
                    break;
                case dataModel.judgeState.state.Compiling:
                    state = OnlineJudge.JudgeState.Compiling;
                    break;
                case dataModel.judgeState.state.Complete:
                    state = OnlineJudge.JudgeState.Complete;
                    break;
                case dataModel.judgeState.state.Crash:
                    state = OnlineJudge.JudgeState.Crash;
                    break;
                case dataModel.judgeState.state.SpecialJudgeProgramLost:
                    state = OnlineJudge.JudgeState.SpecialJudgeProgramLost;
                    break;
                case dataModel.judgeState.state.WaitForCompile:
                    state = OnlineJudge.JudgeState.WaitForCompile;
                    break;
                case dataModel.judgeState.state.WaitForRun:
                    state = OnlineJudge.JudgeState.WaitForRun;
                    break;
                case dataModel.judgeState.state.ZeroTest:
                    state = OnlineJudge.JudgeState.ZeroTest;
                    break;
                default:
                    state = OnlineJudge.JudgeState.Processing;
                    break;
            }
            JudgeValue = OnlineJudge.JudgeReportBase.GetJudgeValue(Result, state);
        }
        /// <summary>
        /// 临时测试集合
        /// </summary>
        protected static readonly List<int> testIds = new List<int>(new int[] { 1 });
        /// <summary>
        /// 程序语言压缩索引
        /// </summary>
        protected static readonly pointer.reference languageIndexs;
        /// <summary>
        /// 程序语言压缩容器大小
        /// </summary>
        public static readonly int LanguageIndexSize;
        unsafe static judgeState()
        {
            languageType[] languages = (languageType[])System.Enum.GetValues(typeof(languageType));
            int languageSize = languages.maxKey(value => (int)(byte)value, -1) + 1, index = 0;
            languageIndexs = unmanaged.Get(languageSize * sizeof(int), false).Reference;
            fastCSharp.unsafer.memory.Fill(languageIndexs.Byte, uint.MaxValue, languageSize);
            foreach (languageType language in languages) languageIndexs.Int[(byte)language] = index++;
            LanguageIndexSize = index;
        }
        
        public bool NeedCompare()
        {
            if(State != state.Compiled && State != state.Complete)
                return false;            
            
            if(Result != OnlineJudge.JudgeResult.Accepted && Result != OnlineJudge.JudgeResult.TimeLimitExceed && 
                Result != OnlineJudge.JudgeResult.WrongAnswer && Result != OnlineJudge.JudgeResult.MemoryLimitExceed &&
                Result != OnlineJudge.JudgeResult.RunTimeError)
                return false;

            return true;
        }
        public bool NeedCompare(judgeState other)
        {
            if (!other.NeedCompare())
                return false;

            if (Result != other.Result)
                return false;

            if (ErrorCount != other.ErrorCount)
                return false;

            int t1 = TimeUse + 30, t2 = other.TimeUse + 30;
            long m1 = MemoryUse, m2 = other.MemoryUse;

            if (t1 * 2 < t2 || t2 * 2 < t1)
                return false;

            if (m1 * 2 < m2 || m2 * 2 < m1)
                return false;

            int lan1 = LanguageCode();
            int lan2 = other.LanguageCode();

            if (lan1 != lan2)
                return false;

            if (lan1 == 0 && Language != other.Language)
                return false;

            return true;
        }

        public int LanguageCode()
        {
            switch (Language)
            {
                case languageType.C:
                case languageType.C11:
                    return 1;
                case languageType.CPlus:
                case languageType.CPlus11:
                case languageType.VCPlus:
                case languageType.OC:
                    return 2;
                case languageType.PyPy2:
                case languageType.Python2:
                    return 3;
                case languageType.PyPy3:
                case languageType.Python3:
                    return 4;
            }

            return 0;
        }

        public static double Similarity(string content1, string content2)
        {
            var cArray1 = content1.Split(new char[] { '\n', '\r', '}', '{' }).Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x)).ToArray();
            var cArray2 = content2.Split(new char[] { '\n', '\r', '}', '{' }).Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x)).ToArray();
            int[] hash1 = cArray1.Select(x => x.GetHashCode()).ToArray();
            int[] hash2 = cArray2.Select(x => x.GetHashCode()).ToArray();

            int len1 = cArray1.Select(x => x.Length).Sum();
            int len2 = cArray2.Select(x => x.Length).Sum();
            int m = hash1.Length, n = hash2.Length;

            int[][] matrix = new int[2][];
            matrix[0] = new int[m + 1];
            matrix[1] = new int[m + 1];

            for (int i = 1; i <= m; i++)
            {
                var tmp1 = matrix[i % 2];
                var tmp2 = matrix[(i + 1) % 2];

                for (int j = 1; j <= n; j++)
                {
                    if (hash1[i - 1] == hash2[j - 1])
                        tmp1[j] = tmp2[j - 1] + cArray1[i - 1].Length;
                    else
                        tmp1[j] = Math.Max(tmp1[j - 1], tmp2[j]);
                }
            }

            return (double)matrix[m % 2][n] * 2 / (len1 + len2);
        }
    }
}